3.3.3 处理器函数
上一小节对处理器进行了介绍,那么什么是处理器函数呢?处理器函数实际上就是与处理器拥有相同行为的函数:这些函数与 ServeHTTP
方法拥有相同的签名,也就是说,它们接受 ResponseWriter
和指向 Request
结构的指针作为参数。代码清单3-8展示了如何在服务器中使用处理器函数。
代码清单3-8 使用处理器函数处理请求
package main
import (
"fmt"
"net/http"
)
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello!")
}
func world(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "World!")
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/hello", hello)
http.HandleFunc("/world", world)
server.ListenAndServe()
}
处理器函数的实现原理是这样的:Go语言拥有一种 HandlerFunc
函数类型,它可以把一个带有正确签名的函数 f
转换成一个带有方法 f
的 Handler
。比如说,对下面这个 hello
函数来说:
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello!")
}
程序只需要执行以下代码:
helloHandler := HandlerFunc(hello)
就可以把 helloHandler
设置成一个 Handler
。如果你对此感到疑惑,那么不妨回顾一下之前展示过的接受处理器的服务器代码:
type MyHandler struct{}
func (h *MyHandler) ServeHTTP (w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World!")
}
func main() {
handler := MyHandler{}
server := http.Server{
Addr: "127.0.0.1:8080",
Handler: &handler,
}
server.ListenAndServe()
}
这个程序使用了以下这行代码来绑定URL地址 /hello
和 hello
函数:
http.Handle("/hello", &hello)
这行代码向我们展示了 Handle
函数将一个处理器绑定至URL的具体方法。此外,在接受处理器函数的代码清单3-8中, HandleFunc
函数会将 hello
函数转换成一个 Handler
,并将它与 DefaultServeMux
进行绑定,以此来简化创建并绑定 Handler
的工作。换句话说,处理器函数只不过是创建处理器的一种便利的方法而已。代码清单3-9展示了 http.HandleFunc
函数的具体定义。
代码清单3-9 http.HandleFunc
函数的源代码
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
而下面是 ServeMux.HandleFunc
方法的定义:
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter,
*Request)) {
mux.Handle(pattern, HandlerFunc(handler))
}
注意这个方法是如何使用 HandlerFunc
函数将传入的 handler
函数转换成真正的处理器的。
虽然处理器函数能够完成跟处理器一样的工作,并且使用处理器函数的代码比使用处理器的代码更为整洁,但是处理器函数并不能完全代替处理器。这是因为在某些情况下,代码可能已经包含了某个接口或者某种类型,这时我们只需要为它们添加 ServeHTTP
方法就可以将它们转变为处理器了,并且这种转变也有助于构建出更为模块化的Web应用。